#include <stdio.h>
#include "raylib.h"
#include "types.h"
#define DYN_STR_IMPLEMENTATION
#include "dynamic_string.h"

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define TARGET_FPS 60
#define MARGIN 10
#define PREVIEW_LINES 10

const char *pcwd;

typedef struct picker_window {
    i32 x;
    i32 y;
    i32 width;
    i32 height;
    i32 margin;
    u32 font_size;
    Color list_color;
} picker_window;

const picker_window pwin = {
    .x = 10,
    .y = 10,
    .width = SCREEN_WIDTH - 2*MARGIN,
    .height = 160,
    .margin = 10,
    .font_size = 16,
    .list_color = DARKGRAY,
};

typedef struct preview_csv_window {
    i32 x;
    i32 y;
    i32 width;
    i32 height;
    i32 margin;
    u32 font_size;
    Color grid_bg;
    Color grid_lines;
} preview_csv_window;

const preview_csv_window pcsv = {
    .x = 10,
    .y = 10,
    .width = SCREEN_WIDTH - 2*MARGIN,
    .height = SCREEN_HEIGHT,
    .margin = 10,
    .font_size = 16,
    .grid_bg = LIGHTGRAY,
    .grid_lines = DARKGRAY
};

typedef struct String_Builder_Array CSV_Paths;

typedef struct String_Builder_Array Raw_CSV_Row;

typedef struct String_Builder_Array_2D Raw_CSV;

String_Builder cwd = {0};
String_Builder csv_path = {0};
String_Builder csv_raw = {0};
String_View cwd_view = {0};
String_View csv_path_view = {0};
String_View csv_raw_rows = {0};
String_View csv_raw_columns = {0};
CSV_Paths csv_paths = {0};
Raw_CSV raw_csv = {0};

typedef enum active_window_t {
    AW_PICKER = 0,
    AW_SHOW,
    AW_LEN,
} active_window_t;

active_window_t active_window = AW_PICKER;

void draw_raw_csv(void) {
    i32 y_offset = pcsv.y + 3*(pcsv.font_size + pcsv.margin);
    Rectangle rec = {
        .x = pcsv.x,
        .y = y_offset,
        .width = pcsv.width,
        .height = pcsv.height - pcsv.margin - y_offset,
    };
    DrawRectangle(
        rec.x,
        rec.y,
        rec.width,
        rec.height,
        pcsv.grid_bg
    );
    i32 row_offset = rec.y;
    for(u64 row=0; row<raw_csv.length; ++row) {
        Raw_CSV_Row line = raw_csv.items[row];
        i32 col_offset = rec.x+pcsv.margin;
        for(u64 i=0; i<line.length; ++i) {
            const char *text = line.items[i].items;
            DrawText(
                text,
                col_offset,
                row_offset,
                pcsv.font_size,
                DARKGRAY
            );
            col_offset += pcsv.margin + MeasureText(text, pcsv.font_size);
        }
        row_offset += pcsv.font_size;
    }
}

void parse_csv_raw(void) {
    csv_raw.length = 0;
    sb_read_entire_file(csv_path_view.data, &csv_raw);
    
    csv_raw_rows.data = csv_raw.items;
    csv_raw_rows.length = csv_raw.length;
    Raw_CSV_Row row = {0};
    String_Builder sb = {0};
    u64 total_bytes = 0;
    for(u64 i=0; i<PREVIEW_LINES; ++i) {
        String_View line = sv_chop_by_delim(&csv_raw_rows, '\n');
        u64 line_bytes = 0;
        u64 length = line.length;
        while(line_bytes < length && length >=1 ) {
            String_View col_sv = sv_chop_by_delim(&line, ',');
            sb_append(&sb, col_sv.data, col_sv.length);
            sb_append_null(&sb);
            sba_append(&row, &sb);
            sb.length = 0;
            line_bytes += col_sv.length;
            // decrement to account for the consumed delimiter 
            length--;
        }
        total_bytes += line_bytes;
        sba2d_append(&raw_csv, &row);
        sba_free(row);
    }
    sb_free(sb);
}

void show_csv(void) {
    DrawText("Selected:", pwin.x, pwin.y, pwin.font_size, LIGHTGRAY);
    DrawRectangle(
        pwin.x, pwin.y+pwin.font_size+pwin.margin, pwin.width, pwin.font_size, LIGHTGRAY
    );
    DrawText(
        csv_path_view.data,
        pwin.x,
        pwin.y+pwin.font_size+pwin.margin,
        pwin.font_size,
        DARKGRAY
    );
    Rectangle rec = {
        .x = pwin.x,
        .y = pwin.y + 2*(pwin.font_size + pwin.margin),
        .width = 80,
        .height = pwin.font_size,
    };
    DrawRectangle(
        rec.x,
        rec.y,
        rec.width,
        rec.height,
        DARKBLUE
    );
    DrawText(
        "Pick File",
        rec.x+pwin.margin,
        rec.y,
        rec.height,
        LIGHTGRAY
    );
    if (
        CheckCollisionPointRec(GetMousePosition(), rec) && \
        IsMouseButtonPressed(MOUSE_BUTTON_LEFT)
    ) {
        active_window = AW_PICKER;
    }

    parse_csv_raw();
    draw_raw_csv();
    sba2d_free(raw_csv);
}

void file_picker(void) {
    FilePathList fpl = {0};
    cwd.length = 0;
    sb_append_cstr(&cwd, GetWorkingDirectory());
    sb_append_null(&cwd);
    cwd_view.data = cwd.items;
    cwd_view.length = cwd.length;
    // Get directory files
    fpl = LoadDirectoryFilesEx(cwd_view.data, ".csv", 0);
    sba_free(csv_paths);
    // Copy paths to memory we control
    for (u32 i=0; i<fpl.count; ++i) {
        sba_append_cstr(&csv_paths, fpl.paths[i]);
    }
    // remove fpl data from raylib arena
    UnloadDirectoryFiles(fpl);
    
    DrawRectangle(
        pwin.x, pwin.y, pwin.width, pwin.height, LIGHTGRAY
    );
    u32 offset = pwin.margin;
    Rectangle rec = {0};
    for(u32 i=0; i<csv_paths.length; ++i) {
        const char *path = csv_paths.items[i].items;
        rec.x = pwin.x + 5;
        rec.y = pwin.y + offset;
        rec.width = pwin.width - pwin.margin;
        rec.height = pwin.font_size;
        if (CheckCollisionPointRec(GetMousePosition(), rec)) {
            DrawRectangle(rec.x, rec.y, rec.width, rec.height, pwin.list_color);
            DrawText(
                path,
                rec.x,
                rec.y,
                pwin.font_size,
                LIGHTGRAY
            );
            if(CheckCollisionPointRec(GetMousePosition(), rec) && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
                memset(csv_path.items, '\0', csv_path.length);
                csv_path.length = 0;
                sb_append_cstr(&csv_path, path);
                sb_append_null(&csv_path);
                csv_path_view.data = csv_path.items;
                csv_path_view.length = csv_path.length;
                active_window = AW_SHOW;
            }
        } else {
            DrawText(
                path,
                pwin.x + 5,
                pwin.y + offset,
                pwin.font_size,
                pwin.list_color
            );
        }
        offset += pwin.font_size;
    }
}

int main(void) {
    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "CSV File Reader");
    SetTargetFPS(TARGET_FPS);
 
    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(DARKGRAY);
        switch (active_window) {
            case AW_PICKER: {
                file_picker();
                break;
            }
            case AW_SHOW: {
                show_csv();
                break;
            }
            default: {
                active_window = AW_PICKER;
                break;
            }
        }
        EndDrawing();
    }
    CloseWindow();

    return 0;
}